﻿using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;

namespace ResourceReportBuilder.Common
{
    public class ResManager
    {
        private ResourceManager _manager;

        private string _resourceFile;
        public string ResourceFile
        {
            get { return _resourceFile; }
        }

        private CultureInfo _culture;
        public CultureInfo Culture
        {
            get { return _culture; }
        }

        public ResManager(string resourceFile, CultureInfo culture)
        {
            _manager = new ResourceManager(string.Format("{0}_Resources", culture.NativeName), Assembly.GetCallingAssembly());
            _resourceFile = resourceFile;
            _culture = culture;
        }

        public ResManager(CultureInfo culture)
        {
            _manager = new ResourceManager(string.Format("{0}_Resources", culture.NativeName), Assembly.GetCallingAssembly());
            _culture = culture;
        }

        public void AddResource(string name, string value)
        {
            using (ResourceWriter writer = new ResourceWriter(_resourceFile))
            {
                try
                {
                    writer.AddResource(name, value);
                }
                finally
                {
                    writer.Close();
                }
            }
        }
        public void AddResource(string name, object value)
        {
            using (ResourceWriter writer = new ResourceWriter(_resourceFile))
            {
                try
                {
                    writer.AddResource(name, value);
                }
                finally
                {
                    writer.Close();
                }
            }
        }
        public void AddResource(string name, byte[] value)
        {
            using (ResourceWriter writer = new ResourceWriter(_resourceFile))
            {
                try
                {
                    writer.AddResource(name, value);
                }
                finally
                {
                    writer.Close();
                }
            }
        }

        public string GetValue(string name)
        {
            return _manager.GetString(name, _culture);
        }

        //public ResourceSet ResourceSet
        //{
        //    get
        //    {

        //        return _manager.GetResourceSet(_culture, false, true);
        //    }
        //}

        public object this[string resourceName]
        {
            get
            {
                return GetValue(resourceName);
            }
        }

        public IDictionaryEnumerator GetEnumerator()
        {
            ResourceReader rdr = new ResourceReader(_resourceFile);
            return rdr.GetEnumerator();
        }


        public static string GetStringResource(string resourceName, Assembly assembly = null)
        {
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }
            using (StreamReader reader = new StreamReader(assembly.GetManifestResourceStream(resourceName)))
            {
                return reader.ReadToEnd();
            }
        }

        public static byte[] GetResourceBuffer(string resourceName, Assembly assembly = null)
        {
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }
            using (Stream str = assembly.GetManifestResourceStream(resourceName))
            {
                if (str == null)
                {
                    throw new ApplicationException(string.Format("Resource '{0}' not found.", resourceName));
                }
                using (BinaryReader reader = new BinaryReader(str))
                {
                    return reader.ReadBytes((int)reader.BaseStream.Length);
                }
            }
        }

        public static Stream GetResourceStream(string resourceName, Assembly assembly = null)
        {
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }
            return assembly.GetManifestResourceStream(resourceName);
        }

        public static string GetResourceFileName(string resourceName, bool hasExtension = true)
        {
            string fileName = string.Empty;
            int extIdx = resourceName.LastIndexOf('.');
            if (extIdx < 0 && hasExtension)
            {
                throw new ApplicationException("Invalid resource name.");
            }
            if (hasExtension)
            {
                string ext = resourceName.Substring(extIdx + 1);

                fileName = resourceName.Substring(0, extIdx);
                int fileNameIdx = fileName.LastIndexOf('.');
                if (fileNameIdx < 0 || fileNameIdx == resourceName.Substring(0, extIdx).Length)
                {
                    throw new ApplicationException("Invalid resource name.");
                }

                fileName = resourceName.Substring(fileNameIdx + 1);
            }
            else
            {
                fileName = extIdx >= 0 ? resourceName.Substring(extIdx + 1) : resourceName;
            }
            return fileName;
        }

        public static void WriteToDisk(string resourceName, string pathOrFileName, Assembly assembly = null, bool overwrite = false, bool hasExtension = true)
        {
            string fileName = string.Empty;
            string ext = Path.GetExtension(pathOrFileName);
            if (string.IsNullOrWhiteSpace(ext))
            {
                fileName = Path.Combine(pathOrFileName, GetResourceFileName(resourceName, hasExtension));
            }
            else
            {
                fileName = pathOrFileName;
            }

            if (File.Exists(fileName) && !overwrite)
            {
                return;
            }

            if (!Directory.Exists(Path.GetDirectoryName(fileName)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            }

            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }
            using (FileStream sw = new FileStream(fileName, FileMode.CreateNew))
            {
                byte[] bytes = GetResourceBuffer(resourceName, assembly);
                sw.Write(bytes, 0, bytes.Length);
            }
        }

        public static void WriteToRelativePath(string resourceName, string ns, Assembly assembly = null, bool overwrite = false, bool hasExtension = true)
        {
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }

            string fileName = GetResourceFullPath(GetResourcePath(Utils.GetRelativePath(ns, resourceName), hasExtension), assembly);

            if (File.Exists(fileName) && !overwrite)
            {
                return;
            }

            if (!Directory.Exists(Path.GetDirectoryName(fileName)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            }

            using (FileStream sw = new FileStream(fileName, FileMode.CreateNew))
            {
                byte[] bytes = GetResourceBuffer(resourceName, assembly);
                sw.Write(bytes, 0, bytes.Length);
            }
        }

        public static string GetResourcePath(string resourceName, bool hasExtension = true)
        {
            int extIdx = hasExtension ? resourceName.LastIndexOf(".") : resourceName.Length;
            if (extIdx <= 0)
            {
                return hasExtension ? string.Empty : resourceName;
            }

            return string.Format("{0}{1}", resourceName.Substring(0, extIdx).Replace(".", "\\"), resourceName.Substring(extIdx));
        }

        public static string GetResourceFullPath(string relativePath, Assembly assembly = null)
        {
            if (assembly == null)
            {
                assembly = Assembly.GetCallingAssembly();
            }

            return Path.Combine(Path.GetDirectoryName(assembly.Location), relativePath.StartsWith("\\") ? relativePath.Substring(1) : relativePath);
        }
    }
}
